<html>
  <head>
    <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/start/jquery-ui.css" />

    <style>
    #picker_launcher {
      margin-bottom: 30px;
    }

    #results {
      font-size: 80%;
      margin-left: 10px;
    }

    button.ui-button {
      margin: 5px;
      font-size: 90%;
      font-weight: bold;
    }

    .media_tab div {
      margin-top: 15px;
    }

    .media_tab label {
      font-weight: bold;
    }

    #media_picker {
      width: 100%;
      height: 100%;
    }

    .failure_msg {
      width: 700px;
    }

    .failure_msg p.failure_link label {
      font-weight: bold;
    }

    .limited_header {
      padding-left: 20px;
      font-size: 100%;
      color: red;
    }

    </style>
    <script src="http://www.google.com/jsapi" type="text/javascript"></script>
    <script type="text/javascript">
    
    LANG = 'en';

    google.load('picker', '1', {'language':LANG});
    google.load("jquery", "1.6.4");
    google.load("jqueryui", "1.8.16");
    google.load("feeds", "1");
    google.setOnLoadCallback(init);
    

    //Global vars

    MEDIA_PICKER_DIV_ID = 'media_picker';
    PICKER_LAUNCHER_DIV_ID = 'picker_launcher';

    RESULTS_DIV_ID = 'results';
    RESULTS_TABS_ID = 'results_tabs';

    PWA_DOMAIN = 'https://picasaweb.google.com/';
    PWA_VID_GADGET_URL = 'http://hosting.gmodules.com/ig/gadgets/file/112339596650419432585/picasa_video.xml'
    //PWA_VID_GADGET_URL = 'http://unchartable.googlecode.com/svn/trunk/misc/sm/picasa_video_embedder.xml'
    
    YT_CONTROLS_HEIGHT = 35;

    WIDE_VIDEO_RES = [
        {width: 240, height: 135}, {width: 320, height: 180},
        {width: 480, height: 270}, {width: 560, height: 315},
        {width: 853, height: 480}, {width: 1280, height: 720},
        {width: 1920, height: 1080}
    ];

    REG_VIDEO_RES = [
        {width: 240, height: 180}, {width: 320, height: 240},
        {width: 480, height: 360}, {width: 640, height: 480}
    ];

    //TODO: Remove comment
    //PWA slideshow sizes: 0,72,144,160,200,288,320,400,512,576,640,720,800
    SLIDESHOW_RES = [
        {width: 200, height: 150}, {width: 288, height: 216},
        {width: 320, height: 240}, {width: 400, height: 300},
        {width: 512, height: 384}, {width: 576, height: 432},
        {width: 640, height: 480}
    ];

    WIDE_IMG_WIDTHS = [50, 100, 150, 200, 250, 300, 350, 400, 450, 500];
    TALL_IMG_WIDTHS = [50, 100, 150, 200, 250, 300, 350, 400, 450, 500];
    ICON_IMG_WIDTHS = [32, 64, 128];

    //TODO: Use this:
    PHOTO_WIDTHS = [50, 100, 150, 200, 250, 300, 350, 400, 450, 500];

    AUTOPLAY = 1;

    //Flashvars for youtube and picasa slideshow players
    DEFAULT_FLASH_VARS = {};

    DEFAULT_FLASH_VARS['yt'] = {
        allowfullscreen: 'true',
        allowscriptaccess: 'always',
        modestbranding: '1',
        showinfo: '0',
        rel: '0',
        wmode: 'opaque'
    }
    
    PWA_PLAYER = 'http://www.youtube.com/get_player?enablejsapi=1';
    
    DEFAULT_FLASH_VARS[PWA_PLAYER] = {
        allowfullscreen: 'true',
        allowscriptaccess: 'always',
        modestbranding: '1',
        showinfo: '0',
        rel: '0',
        wmode: 'opaque'
    }    
    
    PWA_SLIDESHOW_PLAYER = 'https://picasaweb.google.com/s/c/bin/slideshow.swf';
    
    DEFAULT_FLASH_VARS[PWA_SLIDESHOW_PLAYER] = {
        allowfullscreen: 'true',
        allowscriptaccess: 'always',
    }
    
    
    MSG_INSTRUCTIONS =
      '<h2>Instructions</h2>' +
      '<p>Welcome to the Map & Media Picker Gadget. You can ' +
      'use this tool to get links and embed code for: ' +
      '<ul><li>Map locations</li>' +
      '    <li>Picasa photos, videos and slideshows</li>' +
      '    <li>YouTube videos</li>' +
      '    <li>Uploaded photos and webcam recordings</li>' +
      '    <li>Photos and videos found on the web</li>' +
      '</ul></p>' +       
      '<p>Click on any of the big buttons above to start the process!</p>' + 
      '<br><br>';
      
      
    MSG_LIMITED_WARNING =
      '<h3>Warning: Limited Access Albums</h3>' +

      '<p>When you select a photo, video or slideshow from a Picasa album that has ' +
      '"Limited, anyone with a link" sharing you provide an "authorization ' +
      'key" to access that content. This is required to embed items from a ' + 
      '"Limited" album. This includes your <a target="_blank" href="' + 
      'http://support.google.com/picasa/bin/answer.py?hl=en&answer=73970">' + 
      'Picasa DropBox</a> album.</p>' +      

      '<p>Please note that this authorization key could be ' +
      'retrieved and used by someone to view any and all the photos/videos in' + 
      'that album with "Limited, anyone with a link" sharing.</p>' +

      '<p>Any photos & videos you upload using this tool, including any ' +
      'webcam recordings made here will be put into your Picasa DropBox, ' +
      'which is an "Limited, anyone with a link" access album.</p>' +

      '<p>If you don\'t want to accidently give someone access to the other ' +
      'photos and videos in your DropBox or other "Limited, anyone with a link"' + 
      ' albums, you should move or copy the items you want to embed to ' +
      'a different album which is "Public on the web".</p>' +

      '<p><strong>This tool will warn you if you choose an item from a "Limited" ' +
      'album and remind you about this issue.</strong></p>' +

      '<p>Find more information about Picasa album sharing here:' +
      '<ul><li><a target="_blank" href="http://support.google.com/picasa/' +
      'bin/answer.py?hl=en&answer=39551">Sharing options for Picasa</a>' +
      '    <li><a target="_blank" href="http://support.google.com/picasa/' +
      'bin/answer.py?hl=en&answer=39551">Picasa sharing options for Google Apps users</a>' +
      '<li><a target="_blank" href="http://support.google.com/picasa/bin/' +
      'answer.py?hl=en&answer=48446">About authkeys and how to reset them.</a>' +
      '</ul></p>';
    
    
    MSG_IMG_LINK = 'Direct link to image: ';
    MSG_LINK_PICASA_ALBUM = 'Link to private Picasa Album: ';
    MSG_LINK_PICASA_VIDEO = 'Link to video on Picasa: ';
    
    MSG_IMG_EMBED_CODE = 'Image embed code: ';
    MSG_GADGET_EMBED_CODE = 'Picasa video embed code: ';
    MSG_PWA_SLIDESHOW_CODE = 'Slideshow embed code: ';
    MSG_YT_EMDED_CODE = 'YouTube embed code: ';
    
    MSG_LEARN_MORE = 'Learn more';
    MSG_ITEM_LIMITED_ALBUM = 'This item is from an "Limited" access Picasa album.';
    MSG_LOCATION_NAME = 'Location Name: ';
    MSG_ADDRESS = 'Address: ';
    MSG_LAT_LON = 'Latitude & Longitude: ';
    MSG_LOC_LAT_LON = 'Location\'s latitude & longitude';
    MSG_LINK_GMAPS = 'Link to location on Google Maps: ';
    MSG_LINK_YT = 'Link to video on YouTube: ';
    MSG_LINK_IMG = 'Link to photo on website: ';
    MSG_LINK_PHOTO_PWA = 'Link to photo on Picasa: ';
    MSG_LINK_ALBUM_PWA = 'Link to album on Picasa: ';
    
    //Big buttons
    MSG_BUTTON_MAP_LOC = 'Map a location';
    MSG_BUTTON_YOUR_MEDIA = 'Your photos, videos & albums';
    MSG_BUTTON_UPLOAD = 'Upload & Webcam';
    MSG_BUTTON_SEARCH = 'Video & Photo Search';
    MSG_BUTTON_HTML = 'help'
    
    //sub tabs
    MSG_TAB_USAGE = 'How to use this tool';
    MSG_TAB_LIMITED_WARNING = 'About limited albums';
    
    
    MSG_PICASA_ERROR =
      '<h2>Sorry! We can\'t load this photo/video/slideshow from Picasa</h2>' +
      '<p>The item you selected from Picasa is probably in a ' +
      '<a target="_blank" href="http://support.google.com/picasa/bin/' +
      'answer.py?hl=en&answer=39551">"private" or "limited" album</a>, ' +
      'which means you can\'t embed it on another website!</p>' +
      '<p>You either have to make this album "Public on the web" or ' +
      '"Limited, anyone with a link" (<a target="_blank" href="' +
      'http://support.google.com/picasa/bin/answer.py?hl=en&answer=39551' +
      '">more info</a>) OR also copy the photo/video into a ' +
      'new/different album that is "Public" or "Limited" ' +
      '(<a target="_blank" href="http://support.google.com/picasa/bin/' +
      'answer.py?hl=en&answer=62703">more info</a>). Below is a link to ' +
      'your album, in case you want to change the permissions or ' +
      'copy/move your item to another album.</p>' +
      '<p>If you have a Google Apps account, it may not be possible for ' +
      'you to share your albums as "Public" or "Limited, with link" ' +
      '(<a target="_blank" href="http://support.google.com/picasa/bin/' +
      'answer.py?hl=en&answer=187194">more info</a>). In ' +
      'this case you should host your photos or videos on a regular ' +
      'Google account.<p>';
    

    PICKER_TAB_NAMES = {
        map: MSG_BUTTON_MAP_LOC,
        your_media: MSG_BUTTON_YOUR_MEDIA,
        upload: MSG_BUTTON_UPLOAD,
        search: MSG_BUTTON_SEARCH,
        info: MSG_BUTTON_HTML
    }
    


    /**
      Init functions that depend on jquery & picker loading after apis load
    */
    function init () {     

      /**
        Extracts params from a URL parameter string and returns an object
      */
      function getParamsFromUrl(url) {
        //From: http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
        var urlParams = {};
        (function () {
            var e,
                a = /\+/g,  // Replace appendVideoInfo symbol w/ a space
                r = /([^&=]+)=?([^&#]*)/g,
                d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
                q = url;

            while (e = r.exec(q))
               urlParams[d(e[1])] = d(e[2]);
        })();
        return urlParams;
      }     


      /**
        Creates a URL parameter string from an object/associative array
      */
      function getUrlParametersFromArray (obj, delimiter) {
        var urlParams = [];
        for (key in obj) {
          urlParams.push(key + '=' + obj[key]);
        }
        return urlParams.join(delimiter);
      }  


      /**
        Simple object for holding tab sets
       */
      var TabData = function(size, preview, fields) {
        this.size = size;
        this.preview = preview;
        this.fields = [];
        this.build(fields);
      };
      

      TabData.prototype = {
        build: function (fields) {        
          for (var i=0; i < fields.length; i++) {
            this.fields.push({
              name: fields[i][0],
              value: fields[i][1],
              type: fields[i][2],
              link: fields[i][3]});
          }
        }
      };


      /**
        Creates a Picasa feed base URL given user, album and optional authkey
      */
      function getPicasaBaseFeed(user_id, album_id, authkey) {
        var feed_url = PWA_DOMAIN + 'data/feed/api/user/' + user_id + 
            '/albumid/' + album_id;
        feed_url += (authkey != '') ? '?authkey=' + authkey + '&': '?';
        return feed_url;
      }


      /**
        Creates a Picasa video feed URL given user, album, video, & opt. authkey
      */
      function getPicasaVideoFeed (user_id, album_id, video_id, authkey){
        return getPicasaBaseFeed(user_id, album_id, authkey) +
            'alt=rss&fields=item[gphoto:id=\'' + video_id + '\']';
      }


      /**
        Creates a Picasa album feed URL given user, album and optional authkey
      */
      function getPicasaAlbumFeed (user_id, album_id, authkey){
        return getPicasaBaseFeed(user_id, album_id, authkey) +
            'alt=rss&kind=photo&hl=en_US';
      }


      /**
        Detects cropped Picasa photo URLs & returns URL of desired width
      */
      function picasaUrlFormatter (img_url, width) {
        var url_array = img_url.split('/');
        //Largest thumbnail for small image in Picasa contains cropped image
        // resolutions. For large images this doesn't happen. Check just in case.
        if (url_array[url_array.length - 2].search(/s[0-9]+(-c)?/) != -1)
          url_array.splice(url_array.length - 2, 1, 'w' + width);
        else
          url_array.splice(url_array.length - 1, 0, 'w' + width);
        return url_array.join('/');
      }


      /**
        Fetches an ATOM feed using Feeds API & sends results to callback
      */
      function fetchFeed (feed_url, callback, callback_params) {
        var feed = new google.feeds.Feed(feed_url);
        feed.setResultFormat(google.feeds.Feed.XML_FORMAT);
        feed.load(function(result) {
          if (result.error) {
            console.log('Error: ' + feed_url + ' (' +result.error.code + ') ' +
                result.error.message);
            picasaFeedFailureContent(callback_params);
            return false;
          }
          callback(result, callback_params);
        });
      }  


      /**
        Extracts data from Picasa Video feed needed to create embed/preview code
      */
      function getPicasaFeedVideoData (video) {
        var data = {};
        if (video.getNamedItem('medium').value == 'video') { 
          data.width = parseInt(video.getNamedItem('width').value);
          data.height = parseInt(video.getNamedItem('height').value);
          data.wide_screen = (data.width / data.height > 1.4);

          //Construct fmt_list & fmt_stream_map       
          var video_url = video.getNamedItem('url').value;
          var video_params = video_url.split('?')[1];
          var itag = getParamsFromUrl(decodeURIComponent(video_params)).itag;
          var size = data.width + 'x' + data.height;
          var fmt_info = (itag == 5) ?
              [itag, size, 7, 0, 0]: [itag, size, 9, 0, 115];
              
          data.fmt_list = fmt_info.join('/');
          data.fmt_stream_map = [itag, video_url.replace(/,/g, '%2C')].join('|');
          return data;
        }
        return false;
      }    


      /**
        Picasa Video embed code generator; yields a Google Gadget embed script
      */
      var getPicasaVideoEmbedCode = function (width, height, params) {
        var url_params = {
          url: PWA_VID_GADGET_URL, 
          up_user_id: params.user_id,
          up_album_id: params.album_id,
          up_video_id: params.video_id,
          up_authkey: params.authkey,
          up_autoplay: 0,
          up_autohide: 0,
          w: width,
          h: height,
          synd: 'open',
          output: 'js',
          title: ''
        }
        return '<' + 'script src="http://www.gmodules.com/ig/ifr?' + 
            getUrlParametersFromArray(url_params, '&amp;') + '"></' + 'script>';
      }
      

      /**
        Picasa Video preview code generator (direct embed of expiring videos)
        
        Embed code for Picasa Videos uses a Google Gadget, so instead of
        adding <script> tags to the DOM, just directly add the video in the same
        way that the Gadget does.
      */
      var getPicasaVideoPreviewCode = function (
          width, height, fmt_list, fmt_stream_map) {
        var flash_attr = DEFAULT_FLASH_VARS[PWA_PLAYER];
        var flashvars = {
          'fs': 1, 'hl': 'en', 'ps': 'picasaweb', 'playerapiid': 'uniquePlayerId',
          'video_id': 'picasacid', 't': 1, 'auth_timeout': 86400000000,
          'vq': 'auto', //large
          'autoplay': AUTOPLAY,
          'fmt_list': encodeURIComponent(fmt_list.join(',')),
          'fmt_stream_map': encodeURIComponent(fmt_stream_map.join(','))
        };
        flash_attr.flashvars = getUrlParametersFromArray(flashvars, '&');
        return makeFlashEmbedCode(PWA_PLAYER, width, height, flash_attr);
      }


      /**
        Async Picasa Video Feed Fetcher that adds tabs after feed is fetched
      */
      var getPicasaVideoAsyc = function (
          doc, feed_url, user, authkey, has_authkey) {
        callback_params = {
          media_url: doc.url, 
          user_id: user, 
          album_id: doc.parentId,
          video_id: doc.id, 
          authkey: authkey,
          has_authkey: has_authkey};
        fetchFeed(feed_url, getPicasaVideoEmbedSet, callback_params);
      }


      /**
        Try to fetch a Picasa Album; failure usually denotes a private album
      */
      var checkForPrivatePicasaAlbum = function (doc, feed_url, callback) {
        callback_params = {media_url: doc.url};
        fetchFeed(feed_url, callback, callback_params);
      }


      /**
        YouTube Video Handler
      */
      var getYouTubeEmbedSet = function (embed_url, max_height, is_wide) {
        var video_sizes = (is_wide) ? WIDE_VIDEO_RES : REG_VIDEO_RES;
        var embed_set = [];
        for (var i=0; i < video_sizes.length; i++) {
          var size = video_sizes[i];
          if (size.height <= max_height) {
            var preview_code = makeFlashEmbedCode(
                embed_url, size.width, size.height + YT_CONTROLS_HEIGHT,
                DEFAULT_FLASH_VARS['yt']);
            var tab_name =  size.width + 'x' + size.height;
            embed_code = preview_code.clone().wrap('<div>').parent().html();
            var text_fields = [[MSG_YT_EMDED_CODE, embed_code, 'input', false]];
            var tab = new TabData(tab_name, preview_code, text_fields);
            embed_set.push(tab);
          }
        }
        return embed_set;
      }


      /**
        Picasa Video Handler
      */
      var getPicasaVideoEmbedSet = function (result, params) {
        var fmt_list = [];
        var fmt_stream_map = [];
        var video_params = false;

        var xml_results = google.feeds.getElementsByTagNameNS(
            result.xmlDocument.getElementsByTagName('item')[0],
            'http://search.yahoo.com/mrss/', 'content');

        var max_width = 0;
        for (var i = 0; i < xml_results.length; i++) {
          video_params = getPicasaFeedVideoData(xml_results[i].attributes);
          if (video_params) {
            fmt_list.push(video_params.fmt_list);
            console.log(video_params.fmt_stream_map);
            fmt_stream_map.push(video_params.fmt_stream_map);
            if (video_params.width > max_width) {
              max_width = video_params.width;
            }
          }
        }
        if (fmt_list && fmt_stream_map) {
          //Reverse because highest res version need to be first
          fmt_list.reverse();
          fmt_stream_map.reverse();
          var video_sizes = (video_params.wide_screen) ?
              WIDE_VIDEO_RES : REG_VIDEO_RES;

          var embed_set = [];
          for (var i=0; i < video_sizes.length; i++) {
            var size = video_sizes[i];
            if (size.width <= max_width) {
              var preview_code = getPicasaVideoPreviewCode(
                  size.width, size.height + YT_CONTROLS_HEIGHT,
                  fmt_list, fmt_stream_map);
              var embed_code = getPicasaVideoEmbedCode(
                  size.width, size.height + YT_CONTROLS_HEIGHT, params);
              var tab_name =  size.width + 'x' + size.height;
              var text_fields = [[MSG_GADGET_EMBED_CODE, embed_code,
                  'input', false]];
              var tab = new TabData(tab_name, preview_code, text_fields);
              embed_set.push(tab);
            }
          }
          appendResultsTabs(embed_set, params.media_url, 
              MSG_LINK_PICASA_VIDEO, params.has_authkey);
        }
        else {
          console.log('No video in this feed.');
        }
      }


      /**
        Photo/Image Handler (for Picasa photos and Image Search)
      */
      var getPhotoEmbedSet = function (doc, url_manipulator) {
        var img = doc.thumbnails[doc.thumbnails.length - 1];

        /*
        For small imags/icons (e.g. 64x64) sometimes the largest thumbnail is
        incorrectly reported as a ropped 72px image (/s72-c/). In this case,
        use the second largest thumbnail as a more accurante measure of the
        original image's size.
       */

       /*
        console.log(img.url);
        if (img.url.search(/\/s[0-9]+(-c)]/) != -1){
          console.log('bad');

          var img = doc.thumbnails[doc.thumbnails.length - 2];
        }
        var aspect = parseInt(img.height) / parseInt(img.width);

        //Images smaller than 72x72px are problably icons, so give icon sizes
        if (img.width <= 128 && img.height <= 128) {
          var img_sizes = ICON_IMG_WIDTHS;
          //Add original resolution of the image if not already in icon sizes
          if (ICON_IMG_WIDTHS.indexOf(img.width) == -1) {
            ICON_IMG_WIDTHS.push(img.width);
          }
        }
        else {
          var img_sizes = (aspect >= 1) ? WIDE_IMG_WIDTHS : TALL_IMG_WIDTHS;
        }
        */

        var aspect = parseInt(img.height) / parseInt(img.width);
        var img_sizes = (aspect >= 1) ? WIDE_IMG_WIDTHS : TALL_IMG_WIDTHS;

        var embed_set = [];
        for (var i=0; i < img_sizes.length; i++) {
          var thumb_width = parseInt(img_sizes[i]);
          var thumb_height = Math.round(thumb_width * aspect);
          var thumb_url = (url_manipulator) ?
              url_manipulator(img.url, thumb_width) : img.url;
          if (thumb_width <= img.width) {
            var embed_code = getImageHtml(thumb_url, thumb_width);
            var tab_name =  thumb_width + 'x' + thumb_height;
            var text_fields = [];
            text_fields.push([MSG_IMG_LINK, thumb_url, 'input', thumb_url]);
            text_fields.push([MSG_IMG_EMBED_CODE, embed_code, 'input', false]);
            var tab = new TabData(tab_name, embed_code, text_fields);
            embed_set.push(tab);
          }
        }
        return embed_set;
      }


      /**
        Picasa Album Handler
      */
      var getPicasaSlideshowEmbedSet = function (doc) {
        var embed_set = [];
        var video_sizes = SLIDESHOW_RES;
        var flash_attr = DEFAULT_FLASH_VARS[PWA_SLIDESHOW_PLAYER];
        flash_attr.pluginspage = 'http://www.macromedia.com/go/getflashplayer';

        var user = doc.url.replace(PWA_DOMAIN, '').split('/', 1)[0];
        var authkey = (doc.url.indexOf('authkey') != -1) ?
            getParamsFromUrl(doc.url.split('?')[1])['authkey'] : '';

        var flashvars = {
          host: 'picasaweb.google.com',
          hl: 'en_US',
          feat: 'flashalbum',
          RGB: '0x000000',
          feed: encodeURIComponent(getPicasaAlbumFeed(user, doc.id, authkey))
        }
        if (!AUTOPLAY){
          flashvars.noautoplay = 1;
        }
        flash_attr.flashvars = getUrlParametersFromArray(flashvars, '&');
        for (var i=0; i < video_sizes.length; i++) {
          var size = video_sizes[i];
          var preview_code = makeFlashEmbedCode(
              PWA_SLIDESHOW_PLAYER, size.width, size.height, flash_attr);
          embed_code = preview_code.clone().wrap('<div>').parent().html();
          var tab_name =  size.width + 'x' + size.height;
          var text_fields = [[MSG_PWA_SLIDESHOW_CODE, embed_code, 'input', false]];
          var tab = new TabData(tab_name, preview_code, text_fields);
          embed_set.push(tab);
        }
        return embed_set;
      }   


      /**
        Creates HTML for a <img>
      */
      var getImageHtml = function (src, width) {      
        return (width) ? '<img width="' + width + '" style="width: ' + width +
            'px" src="' + src + '" />' : '<img src="' + src + '" />';
      }     


      /**
        Creates HTML for a linked <img>
      */
      var getLinkedImageHtml = function (src, width, href, new_window) {
        var target = (typeof new_window == 'undefined') ? '' : 'target="_blank"';
        return '<a href="' + href + '" ' + target + '>' + 
            getImageHtml(src, width) + '</a>';
      }

      
      /**
        Generic Flash embed code generator (for YouTube, Picasa Videos & Albums)
      */
      var makeFlashEmbedCode = function (swf_url, width, height, params) {
        var object = $('<object></object>').attr({width: width, height: height});
        for (item in params) {
          object.append($('<param />').attr({name: item, value: params[item]}));
        }
        object.append($('<param />').attr({name: 'movie', value: swf_url}));
        params.type = "application/x-shockwave-flash";
        params.src = swf_url;
        var embed = $('<embed />').attr(params);
        object.append(embed.attr({width: width, height: height}));
        return object;
      }
      

      /**
        Create text input & opt. image link for users to copy/view content URLs
       */
      var getLabelTextFieldHtml = function (label, value, width, link) {
        width = typeof width !== 'undefined' ? width : 50;
        link = typeof link !== 'undefined' ? link : false;
        make_link = typeof make_link !== 'undefined';
        var div = $('<div></div>').addClass('media_embed').append(
          $('<label>' + label + '</label>'),
          $('<input></input>', {
              readonly: 'readonly',
              type: 'text',
              value: value,
              size: width
          }).addClass('url_box')
        );
        if (link) div.append(getLinkedImageHtml('open.gif', false, link, true));
        return div;
      }
      

      /**
        Create a hyperlink with optioanlly truncated URL as link name
       */
      var getLinkFieldHtml = function (label, href, name, truncate) {
        if (truncate && name.length > 40) {
          name = name.slice(0, 40) + '...';
        }
        return $('<div></div>').addClass('media_link').append(
          '<label>' + label + '</label>',
          '<a target="_blank" href="' + href + '">' + name + '</a>'
        );
      }
      

      /**
        Clear existing tabs/content and create new ones
       */
      var makeTabs = function (content_items) {
        var results_div = $('#' + RESULTS_DIV_ID);        
        //Hide and then destroy existing tabs before adding new ones
        results_div.hide().tabs('destroy').empty();
        
        $.each(content_items, function (index, item) {
          results_div.append(item);
        });
        //Make the tabs selectable
        $('input.url_box').click(function() {
          this.focus();
          this.select();
        });
        //Build the tabs
        results_div.tabs().show();
        return results_div;
      }
      

      /**
        Show tab/content for when Picasa feed fetch fails on private content
       */
      var picasaFeedFailureContent = function (params) {
        var content_items = [];
        var tab_id = 'failure_tabs_';
        content_items.push($('<ul></ul>', {id: RESULTS_TABS_ID})
            .append('<li><a href="#' + tab_id + '">Picasa Error</a></li>'));

        var div = $('<div></div>', {id: tab_id}).addClass('failure_msg');
        //Add source website links to the media asset

        var html = MSG_PICASA_ERROR;

        var album_url = params.media_url.split('#')[0];
        html += '<p class="failure_link">' + MSG_LINK_PICASA_ALBUM + '<br>' +
            '<a target="_blank" href="' + album_url + '">' + album_url +
            '</a></p>';

        content_items.push($('<div></div>', {id: tab_id})
          .addClass('failure_msg').append(html));

        makeTabs(content_items);
      }
      

      /**
        Show the Usage Instructions tab/content
       */
      var usageInstructionsContent = function () {
        var content_items = [];
        var tab_id = 'instructions_tabs_';
        content_items.push($('<ul></ul>', {id: RESULTS_TABS_ID})
            .append('<li><a href="#' + tab_id + '">' + MSG_TAB_USAGE +
                '</a></li>'));

        content_items.push($('<div></div>', {id: tab_id}).append(
            MSG_INSTRUCTIONS + MSG_LIMITED_WARNING));

        makeTabs(content_items);
      }
      

      /**
        Show tabs/content divs for Picked items
       */
      var appendResultsTabs = function (tabs, media_url, media, has_authkey) {
        var content_items = [];

        has_authkey = (typeof has_authkey !== 'undefined') ? has_authkey : false;
        if (has_authkey) {
          var more_button = $('<a id="limited_warning" href="#">' +
              MSG_LEARN_MORE + '</a>');
              //.click(function () {usageInstructionsContent(); return false;});
              
          content_items.push($('<p class="limited_header">' + 
              MSG_ITEM_LIMITED_ALBUM + ' </p> ').append(more_button));
        }
        
        var tab_bar = $('<ul></ul>', {id: RESULTS_TABS_ID});

        
        
        content_items.push(tab_bar);
        $.each(tabs, function(index, tab) {
          var tab_id = 'results_tabs_' + index;
          tab_bar.append('<li><a href="#' + tab_id + '">' + tab.size + '</a></li>');

          var div = $('<div></div>', {id: tab_id}).addClass('media_tab');
          //Add source website links to the media asset
          //div.append(getLinkFieldHtml(media, media_url, media_url, true));
          var asset_link = getLabelTextFieldHtml(media, media_url, 30, media_url);
          div.append(asset_link);

          $.each(tab.fields, function(index, field) {
            div.append(getLabelTextFieldHtml(field.name, field.value, 30, field.link));
          });
          div.append($('<div></div>').addClass('media_preview').append(tab.preview));
          content_items.push(div);
          i = index;
        });
        
        if (has_authkey) {
          tab_id = 'results_tabs_warning';
          tab_bar.append('<li><a href="#results_tabs_warning">' +
              MSG_TAB_LIMITED_WARNING + '</a></li>');

          content_items.push($('<div></div>', {id: tab_id}).append(
              MSG_LIMITED_WARNING));
        }
        var results_div = makeTabs(content_items);
        
        $('#limited_warning').click(function(){
          results_div.tabs('select', '#results_tabs_warning');
          return void(0);
        });
      }
      

      /**
        Create buttons for each Picker type
       */
      var appendPickerTabs = function () {
        for (type in PICKER_TAB_NAMES) {
          var button = $('<button>' + PICKER_TAB_NAMES[type] + '</button>',
              {id: type, type: 'button'});
                  
          switch (type) {
            case 'map':
              button.click(function () {createMapPicker()});
              break;

            case 'your_media':
              button.click(function () {createYourMediaPicker()});
              break;

            case 'upload':
              button.click(function () {createUploadPicker()});
              break;

            case 'search':
              button.click(function () {createSearchPicker()});
              break;

            case 'info':
              button.click(function () {usageInstructionsContent()});
              break;

            default:
              console.log('Unknown Picker request.');
          }

          $('#' + PICKER_LAUNCHER_DIV_ID).append(button);
        }
        $('button', '#' + PICKER_LAUNCHER_DIV_ID).button();
      }
      

      /**
        Handler for map data returned by Picker
       */
      var mapHandler = function (doc) {
        var text_fields = [];
        if (doc.name != 'Untitled Location')
          text_fields.push([MSG_LOCATION_NAME, doc.name, 'input']);

        if (typeof doc.addressLines !== 'undefined') {
          var address = doc.addressLines.join(" ");
          if (doc.name != address)
            text_fields.push([MSG_ADDRESS, address, 'input', false]);
        }
        text_fields.push([MSG_LAT_LON, doc.latitude.toFixed(6) + '\t' +
            doc.longitude.toFixed(6), 'input']);
        var preview_code = getImageHtml(
            doc.thumbnails[3].url, doc.thumbnails[3].width);
        var embed_set = new TabData(MSG_LOC_LAT_LON, preview_code, text_fields);

        appendResultsTabs([embed_set], doc.url, MSG_LINK_GMAPS);
      }
      

      /**
        Handler for Picasa data returned by Picker
       */
      var picasaHandler = function (doc) {
        var user = doc.url.replace(PWA_DOMAIN, '').split('/', 1)[0];
        var authkey = (doc.url.indexOf('authkey') != -1) ?
            getParamsFromUrl(doc.url.split('?')[1])['authkey'] : '';
        var has_authkey = (authkey != '');

        switch (doc.type) {
          case 'video':
            var video_feed = getPicasaVideoFeed(user, doc.parentId, doc.id, authkey);
            console.log(video_feed);
            getPicasaVideoAsyc(doc, video_feed, user, authkey, has_authkey);
            break;

          case 'photo':
            var album_feed = getPicasaAlbumFeed(user, doc.parentId, authkey);
            checkForPrivatePicasaAlbum(doc, album_feed, function () {
                var embed_set = getPhotoEmbedSet(doc, picasaUrlFormatter);
                appendResultsTabs(embed_set, doc.url, MSG_LINK_PHOTO_PWA, has_authkey);
            });
            break;

          
          case 'album':
            var album_feed = getPicasaAlbumFeed(user, doc.id, authkey);
            checkForPrivatePicasaAlbum(doc, album_feed, function () {
                var embed_set = getPicasaSlideshowEmbedSet(doc);
                appendResultsTabs(embed_set, doc.url, MSG_LINK_ALBUM_PWA, has_authkey);
            });
            break;

          default:
            console.log('Unknown doc type: ' + doc.type);
        }
      }
      

      /**
        Handler for Non-Picasa/Map data returned by Picker
       */
      var defaultHandler = function (doc) {
        switch (doc.type) {
          case 'video':
            var embed_set = getYouTubeEmbedSet(doc.embedUrl, 480, false);
            appendResultsTabs(embed_set, doc.url, MSG_LINK_YT);
            break;

          case 'photo':
            var embed_set = getPhotoEmbedSet(doc, false);
            appendResultsTabs(embed_set, doc.url, MSG_LINK_IMG);
            break;

          default:
            console.log('Unknown doc type: ' + doc.type);
        }
      }
      

      /**
        Create a Map Picker
       */
      var createMapPicker = function () {
        var picker = new google.picker.PickerBuilder()
          .enableFeature(google.picker.Feature.NAV_HIDDEN)
          .addView(new google.picker.MapsView())
          .setCallback(pickerCallback)
          .build();
        picker.setVisible(true);
      }
      

      /**
        Create a Picker for user's Picasa and YouTube photos/videos
       */
      var createYourMediaPicker = function () {
        var picker = new google.picker.PickerBuilder()
          .addView(google.picker.ViewId.PHOTOS)
          .addView(new google.picker.PhotosView()
              .setType(google.picker.PhotosView.Type.UPLOADED))
          .addView('photo-albums')
          .addView(google.picker.ViewId.YOUTUBE)
          .setCallback(pickerCallback)
          .build();
        picker.setVisible(true);
      }
      

      /**
        Create a Picker for uploading photos and videos to Picasa DropBox
       */
      var createUploadPicker = function () {
        var picker = new google.picker.PickerBuilder()
          .addView('upload/photos')
          .addView('upload/videos')
          .addView(new google.picker.PhotosView()
              .setType(google.picker.PhotosView.Type.UPLOADED))
          .addView(google.picker.ViewId.WEBCAM)
          .setCallback(pickerCallback)
          .setUploadToAlbumId('-1')
          .build();
        picker.setVisible(true);
      }
      

      /**
        Create a Picker for Image/Video searches and features photos
       */
      var createSearchPicker = function () {
        var picker = new google.picker.PickerBuilder()
          .addView(google.picker.ViewId.IMAGE_SEARCH)
          .addView(google.picker.ViewId.VIDEO_SEARCH)
          .addView(new google.picker.PhotosView()
              .setType(google.picker.PhotosView.Type.FEATURED))
          .setCallback(pickerCallback)
          .setUploadToAlbumId('-1')
          .build();
        picker.setVisible(true);
      }
      

      /**
        Callback after user Picks something; dispatch to appropriate handler
       */
      var pickerCallback = function (data) {
        //Get first (and only) doc
        var doc = data.docs[0];

        //MapsView() docs don't have a serviceId, so check for doc.latitude
        if (typeof doc.serviceId === 'undefined'
              && typeof doc.latitude !== 'undefined'){
          mapHandler(doc);
        }
        else {
          switch (doc.serviceId) {
            case 'picasa':
              picasaHandler(doc);
              break;

            default:
              defaultHandler(doc);
          }
        }
      }
      
      appendPickerTabs();
      usageInstructionsContent();
  }
    
    /*
    
    function escapeHtml(html) {
      return html.replace(/&/g, "&amp;")
          .replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
    }

    
    */
    
  
    </script>
  </head>
  <body>
    <div id="media_picker" style="overflow: auto;">
      <div id="picker_launcher" style="overflow: auto;"></div>
      <div id="results" style="overflow: auto;"></div>
    </div>
  </body>
</html>